import sys
import copy

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

from Vector import Vector3
from Curve import BezierSpline, BSpline

SCREEN_WIDTH = 720
SCREEN_HEIGHT = 480

SPLINE_TYPES = [BezierSpline, BSpline]
spline_type_index = 1

spline = SPLINE_TYPES[spline_type_index]()
CurveMaxDegree = 5
CurveMinDegree = 1

def DrawBezierSpline():
    # Draw control points
    cps = spline.ControlPoints() 
    glColor3f(1.0, 0.0, 0.0)
    glPointSize(5)
    glBegin(GL_POINTS)
    for p in cps:
        glVertex3fv(p.xyz)
    glEnd()

    # Draw hull
    glBegin(GL_LINE_STRIP)
    for p in cps:
        glVertex3fv(p.xyz)
    glEnd()

    glColor3f(0.0, 1.0, 1.0)
    if spline.SegmentCount() > 0:
        glBegin(GL_LINE_STRIP)
        t = 0
        while t <= 1:
            v = spline.Interpolate(t)
            glVertex3fv(v.xyz)
            t += 0.001
        glEnd()

def DrawText(content):
    glColor3f(1.0, 1.0, 1.0)
    x = 5
    y = SCREEN_HEIGHT - 20
    glRasterPos2f(x, y)
    for c in content:
        if c == '\n':
            y -= 20
            glRasterPos2f(x, y)
        else:
            glutBitmapCharacter(GLUT_BITMAP_9_BY_15, ord(c))

def DisplayCallback():
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluOrtho2D(0, SCREEN_WIDTH, 0, SCREEN_HEIGHT)

    glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)

    # Draw text
    windowMessage = 'Switch Spline Type: %1s (F1)\n' % (SPLINE_TYPES[spline_type_index].__name__) 
    windowMessage += 'Degree : %1d (F2/F3)\n' % (spline.degree)
    windowMessage += 'Clear : (F4)\n'
    windowMessage += 'Knots : %1s\n' % str(spline.knots)
    DrawText(windowMessage)
   
    DrawBezierSpline() 

    glutSwapBuffers()

def MouseCallback(button, state, x, y):
    if button == GLUT_LEFT_BUTTON and state == GLUT_UP:
        global spline
        spline.AppendControlPoint(Vector3(x, SCREEN_HEIGHT - y))
        glutPostRedisplay()

def KeyboardCallback(key, x, y):
    pass

def SpecialKeyboardCallback(key, x, y):
    print key 
    global spline 
    if key == 1:
        global spline_type_index
        spline_type_index = (spline_type_index + 1) % len(SPLINE_TYPES)
        global spline
        spline = SPLINE_TYPES[spline_type_index](copy.deepcopy(spline.ControlPoints()), spline.degree)
        glutPostRedisplay()
    elif key == 2 and spline.degree < CurveMaxDegree:
        spline.degree += 1
        glutPostRedisplay()
    elif key == 3 and spline.degree > CurveMinDegree:
        spline.degree -= 1
        glutPostRedisplay()
    elif key == 4:
        global ControlPoints
        spline.ClearControlPoints()
        glutPostRedisplay()

def main():
    glutInit(len(sys.argv), sys.argv)
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA)
    glutInitWindowSize(SCREEN_WIDTH, SCREEN_HEIGHT)
    glutInitWindowPosition(100, 100)
    glutCreateWindow('Curve')

    glClearColor(0.0, 0.0, 0.0, 0.0)
    glShadeModel(GL_SMOOTH)

    glutDisplayFunc(DisplayCallback)
    glutMouseFunc(MouseCallback)
    glutKeyboardFunc(KeyboardCallback)
    glutSpecialFunc(SpecialKeyboardCallback)

    glutMainLoop()

if __name__ == '__main__':
    main()
